package Animal;

public class TestAnimal {
//编译器在编译代码的时候，并不知道要调用Dog还是Cat中的eat方法
    //等到程序运行起来后，i形参引用的具体对象确定后，才知道调用哪一个方法
    //注意此处的形参类型必须要父亲的类型才可以

    public static void eat(Animal a){
        a.eat();
    }

    public static void main(String[] args) {
        Cat cat=new Cat("元宝",2);
        Dog dog=new Dog("小七",1);

        System.out.println("======================");

        //向上转型：
        Animal animal=cat;
        animal.eat();
        System.out.println("======================");
        if(animal instanceof Cat){
            cat=(Cat)animal;
            cat.mew();
        }
        System.out.println("======================");
        animal=dog;
        animal.eat();
        System.out.println("======================");
        if(animal instanceof Dog){
            dog=(Dog)animal;
            dog.bark();
        }

    }

    public static void main1(String[] args) {
        Cat cat=new Cat("元宝",2);
        Dog dog = new Dog("小七",3);

        Animal animal=new Animal("动物",0);
        Animal cat2=new Cat("元宝",2);
        Animal dog2 = new Dog("小七",3);
        eat(cat);
        eat(dog);
        System.out.println("==========");
        cat.eat();


        //重写：也称为覆盖，重写是子类对父类非静态、非private、非final非构造方法的实现过程的重写
        //返回值和形参都不可以改变
        //即外壳不变核心重写！！重写的好处在于子类可以根据需要，定义特定的于自己的行为欸
        //也就是说子类可以根据需要实现父类的方法
        //
        //重写的规则：
        //子类在重写弗雷德方法时候，一般必须与父类方法原型一致：
        //返回值类型，函数名，参数列表完全一致
        //被重写的方法的返回值类型可以不同，但是必须具有父子关系
        //访问权限不能比父类中被重写的方法权限低，，也就是大于等于
        //父类被static、private修饰的方法、构造方法都不能被重写
        //重写的方法，可以使用@Override注解来显示指定。有了这个注解能帮我们进行一些合法性检验
        //名字拼写错了，都会提醒

        //方法重载是一个类的多态性体现，而方法重写是父类和子类一种多态性体现

        //重写的设计原则，对于已经投入使用的类，尽量不要修改
        //最好的方式是：重新定义一个新的类
        //来重复利用其中共性的内容，并且添加或者改动新的内容


        //静态绑定

        //动态绑定：运行时候，才能够确定去调用哪一个方法

        //向上转型和向下转型
        //

        //向上转型：实际就是船舰一个子类对象，将其当作父类对象来使用
        //语法格式

        Animal animal1=new Cat("花花",3);

        //animal是一个父类类型，但是可以引用一个子类对象，因为是从小范围到大范围转换
        //你自然能理解

        //
    }

    //在上述代码中，分割线上方的diamagnetic是类的实现者编写的，
    //下方是类的调用者

    //当类的调用者在编写eat这个方法的时候，参数类型Animal（父类），此时在方法内部并不知道，也不关注当前的a引用指向的是那个类型（那个子类），或者是父类？？？
    //此时a这个引用调用的eat方阿飞可能会有多种不同的表现
    //和a引用的实例有关
    //这种行为就称为多态


}

//使用场景：
//1.直接赋值---父亲类型的对象可以接受任意子类new的对象
//2.方法传参---父类的形参也可以接受任意子类的对象
//3.方法返回---返回值设置为父类，你将子类返回，用一个父类去可以接收任意子类的对象
//3-----------返回值设置为子类，但是你用父类来接受子类对象

//向上转型的优点：让代码实现更加的灵活

//向上转型的缺陷：不能调用到子类特有的方法

//向下转型：

//当你将一个子类对象经过向上转型后当作父类来用，此时你没有办法调用子类方法
//此时：将父类引用再次还原为i子类对象就可以了
//你注意不要还原错了就是
//还原错了就不安全

//在父类的时候，只能使用父类的方法
//你没有调用子类方法的机会
//

//向下转型使用的是强制类型转换---你转换错了，就会在运行时候报错
//还原正确，就可以调人家的方法了

//为了提高向下转型的正确性
//引入了instanceof，实例之一
//父类之一
//动物之一
//
